package com.zide.member.auth.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zide.common.constant.Constants;
import com.zide.common.constant.HttpStatus;
import com.zide.common.core.domain.model.MemberLoginUser;
import com.zide.common.exception.ServiceException;
import com.zide.common.exception.user.UserPasswordNotMatchException;
import com.zide.common.utils.MessageUtils;
import com.zide.common.utils.SecurityUtils;
import com.zide.common.utils.uuid.NicknameUtil;
import com.zide.framework.manager.AsyncManager;
import com.zide.framework.manager.factory.AsyncFactory;
import com.zide.framework.security.context.AuthenticationContextHolder;
import com.zide.framework.security.utils.MemberUserTokenUtil;
import com.zide.framework.web.domain.vo.save.MemberRegisterVO;
import com.zide.member.auth.domain.vo.MemberUserLoginVO;
import com.zide.member.auth.domain.vo.result.LoginResultVO;
import com.zide.member.auth.service.IAuthLoginService;
import com.zide.common.core.domain.entity.UmsMember;
import com.zide.framework.web.mapper.UmsMemberMapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import java.util.Random;

/**
 * @author 石添
 * @date 2024/2/26 17:43
 */
@Slf4j
@Service
public class AuthLoginServiceImpl implements IAuthLoginService {

    @Resource
    private UmsMemberMapper umsMemberMapper;

    @Resource
    @Qualifier("memberUserAuthenticationManager")
    private AuthenticationManager authenticationManager;
    @Resource
    private MemberUserTokenUtil memberUserTokenUtil;
    /**
     * 根据账号密码登录
     * @param loginVO
     * @return
     */
    @Override
    public LoginResultVO loginByAccountAndPassword(MemberUserLoginVO loginVO) {
        String account = loginVO.getAccount();
        String password = loginVO.getPassword();
        log.info("account====>{}",account);
        log.info("password====>{}",password);
        // 用户验证
        Authentication authentication = null;
        try {
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(account,password);
            AuthenticationContextHolder.setContext(authenticationToken);
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager.authenticate(authenticationToken);
        } catch (Exception e) {
            if (e instanceof BadCredentialsException) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(account, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                throw new UserPasswordNotMatchException();
            } else {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(account, Constants.LOGIN_FAIL, e.getMessage()));
                throw new ServiceException(e.getMessage());
            }
        } finally {
            AuthenticationContextHolder.clearContext();
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(account, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
        MemberLoginUser loginUser = (MemberLoginUser) authentication.getPrincipal();

        String token = memberUserTokenUtil.createToken(loginUser);
        log.info("token=========>{}",token);
        LoginResultVO loginResultVO = new LoginResultVO();
        loginResultVO.setId(loginUser.getId());
        loginResultVO.setNickname(loginUser.getNickname());
        loginResultVO.setAvatar(loginUser.getAvatar());
        loginResultVO.setToken(token);
        return loginResultVO;
    }

    /**
     * 账号密码注册
     */
    @Override
    public LoginResultVO registerByAccount(MemberRegisterVO registerVO) {
        if(checkRegisterByAccount(registerVO)) {
            String avatar = "http://localhost:8128/img/article/20240501180023A002.png";
            // 生成默认头像和昵称注册账号
            UmsMember insertBean = BeanUtil.copyProperties(registerVO, UmsMember.class);
            String nickname = NicknameUtil.getName();
            insertBean.setNickname(nickname);
            insertBean.setAvatar(avatar);
            insertBean.setPassword(SecurityUtils.encryptPassword(registerVO.getPassword()));
            umsMemberMapper.insert(insertBean);
            String token = memberUserTokenUtil.createToken(BeanUtil.copyProperties(insertBean,MemberLoginUser.class));
            LoginResultVO loginResultVO = new LoginResultVO();
            loginResultVO.setId(insertBean.getId());
            loginResultVO.setNickname(nickname);
            loginResultVO.setAvatar(avatar);
            loginResultVO.setToken(token);
            return loginResultVO;
        }
        return null;
    }

    /**
     * 退出登录
     */
    @Override
    public void logout() {

    }

    private boolean checkRegisterByAccount(MemberRegisterVO registerVO) {
        String account = registerVO.getAccount();
        String password = registerVO.getPassword();
        String confirmPass = registerVO.getConfirmPass();

        if(StrUtil.isEmpty(account) || StrUtil.isEmpty(password) || StrUtil.isEmpty(confirmPass)) {
            throw new ServiceException(HttpStatus.ERROR,"账号密码不能为空");
        }
        if(!StrUtil.equals(password,confirmPass)) {
            throw new ServiceException(HttpStatus.ERROR,"两次密码不同");
        }
        // 判断用户是否存在
        UmsMember dbMember = umsMemberMapper.selectOne(new LambdaQueryWrapper<UmsMember>().eq(UmsMember::getAccount, account));
        if(ObjectUtil.isNotNull(dbMember)) {
            throw new ServiceException(HttpStatus.ERROR,"该账号已被使用");
        }
        return true;
    }
    public static String generateChineseName() {
        StringBuilder chineseName = new StringBuilder();
        // Unicode范围：4e00-9fa5 是中文字符的范围
        int unicodeStart = 0x4e00;
        int unicodeEnd = 0x9fa5;
        Random random = new Random();
        //参数控制生成名字的长度（2个字/3个字）
        for (int i = 0; i < random.nextInt(2)+2; i++) {
            // 生成随机中文字符
            char randomChar = (char) (unicodeStart + random.nextInt(unicodeEnd - unicodeStart + 1));
            chineseName.append(randomChar);
        }
        return chineseName.toString();
    }
}
